/** 
 *java Calendar Halper
 *
 * @refer to     java.util.Date/java.util.Calendar/java.util.GregorianCalendar
 * @refer to     java.sql.Date/java.sql.Time/java.sql.Timestamp
 * @refer to     java.util.Locale/java.util.TimeZone
 * @refer to     java.text.DateFormat/java.text.SimpleDateFormat
 * @version      1.0, 2016/06/06
 * @author       yonghua.cao
 * @usage        JDK1.7
 */
package com.hua.utility.utility;

public class UtilCalendar extends java.util.GregorianCalendar {

	private static final long serialVersionUID = -945939951837309866L;

	public static final String className = UtilCalendar.class.getName();

	// DateFormat常用格式
	// G 年代标志符 (格式{G})
	// y 年 (格式{yyyy})
	// M 月 (格式{MM})
	// d 日 (格式{dd})
	// h 时 在上午或下午 (1~12) (格式{hh})
	// H 时 在一天中 (0~23) (格式{HH})
	// m 分 (格式{mm})
	// s 秒 (格式{ss})
	// S 毫秒 (格式{SSSS})
	// E 星期 (格式{E})
	// D 一年中的第几天 (格式{D})
	// F 一月中第几个星期几 (格式{F})
	// w 一年中第几个星期 (格式{w})
	// W 一月中第几个星期 (格式{W})
	// a 上午 / 下午 标记符 (格式{a})
	// k 时 在一天中 (1~24) (格式{k})
	// K 时 在上午或下午 (0~11) (格式{K})
	// z 时区 (格式{z})
	// Z 时区 (格式{Z})

	public static final String FORMATSTRING_FULL = "公元：G  时区(标准):z (数字)Z  时间：yyyy-MM-dd HH:mm:ss:SSS  年中的天数：D  "
			+ "年中的周数：w  月份中的周数 ：W  月份中的星期 ：F  星期中的天数 ：(标准)E(格式)EEE   上午下午标记：a  一天中的小时数（1-24）：k  "
			+ "上午/下午中的小时数（0-11）：K  上午/下午中的小时数（1-12）：h";

	public static final String FORMATSTRING_LONG = "yyyy-MM-dd HH:mm:ss:SSS EEE";

	public static final String FORMATSTRING_DATE_TIME = "yyyy-MM-dd HH:mm:ss:SSS";

	public static final String FORMATSTRING_DEFAULT = "yyyy-MM-dd HH:mm:ss";

	public static final String FORMATSTRING_DATE = "yyyy-MM-dd";

	public static final String FORMATSTRING_TIME = "HH:mm:ss";

	public static final String FORMATSTRING_TIME_LONG = "HH:mm:ss:SSS";

	public static final String FORMATSTRING_STRING_Z = "yyyyMMddHHmmssSSSZ";

	public static final String FORMATSTRING_STRING = "yyyyMMddHHmmssSSS";

	public static final java.time.Month[] Month_OF_YEAR = { java.time.Month.JANUARY, java.time.Month.FEBRUARY,
			java.time.Month.MARCH, java.time.Month.APRIL, java.time.Month.MAY, java.time.Month.JUNE,
			java.time.Month.JULY, java.time.Month.AUGUST, java.time.Month.SEPTEMBER, java.time.Month.OCTOBER,
			java.time.Month.NOVEMBER, java.time.Month.DECEMBER };

	public static final java.time.DayOfWeek[] DAY_OF_WEEK = { java.time.DayOfWeek.MONDAY, java.time.DayOfWeek.TUESDAY,
			java.time.DayOfWeek.WEDNESDAY, java.time.DayOfWeek.THURSDAY, java.time.DayOfWeek.FRIDAY,
			java.time.DayOfWeek.SATURDAY, java.time.DayOfWeek.SUNDAY };

	public static final String[] TIME_UNIT = { "millis", "second", "minute", "hour", "day", "week", "month", "quarter",
			"year", "decade", "century", "millennium", "original" };

	public static final java.util.Locale LOCALE_DEFAULT = java.util.Locale.CHINA;

	public static final long MILLIS_IN_SECOND = 1000L;

	// 1000 * 60
	public static final long MILLIS_IN_MINUTE = 60000L;

	// 1000 * 60 * 60
	public static final long MILLIS_IN_HOUR = 3600000L;

	// 1000 * 60 * 60 * 24
	public static final long MILLIS_IN_DAY = 86400000L;

	// 1000 * 60 * 60 * 24 * 7
	public static final long MILLIS_IN_WEEK = 604800000L;

	public static final String[] CALENDAR_FIELD_NAMES = { "ERA", "YRAR", "MONTH", "WEEK_OF_YEAR", "WEEK_OF_MONTH",
			"DAY_OF_MONTH", "DAY_OF_YEAR", "DAY_OF_WEEK", "DAY_OF_WEEK_IN_MONTH", "AM_PM", "HOUR", "HOUR_OF_DAY",
			"MINUTE", "SECOND", "MILLISECOND", "ZONE_OFFSET", "DST_OFFSET" };

	public static final java.util.Calendar ZERO_GREGORIAN = convertToCalendar(
			parseStringToDate("1970-01-01 00:00:00:000", FORMATSTRING_DATE_TIME));

	@SuppressWarnings("rawtypes")
	private static boolean isEmpty(Object o) {
		Boolean checkResult = false;
		if (o == null) {
			checkResult = true;
		} else if (o instanceof String) {
			if ((o.toString().trim()).length() <= 0) {
				checkResult = true;
			}
		} else if (o instanceof java.util.Collection) {
			if (((java.util.Collection) o).size() <= 0) {
				checkResult = true;
			}
		} else if (o instanceof java.util.Map) {
			if (((java.util.Map) o).size() <= 0) {
				checkResult = true;
			}
		} else if (o instanceof java.lang.CharSequence) {
			if (((java.lang.CharSequence) o).length() <= 0) {
				checkResult = true;
			}
		} else {
			try {
				o.toString();
			} catch (Exception e) {
				throwRuntimeException(o.getClass().getName() + "toString forbidden operation.");
			}
		}
		return checkResult;
	}

	private static void throwRuntimeException(Object o) {
		if (isEmpty(o)) {
			return;
		} else if (o instanceof Throwable) {
			throw new RuntimeException(className + ":" + ((Throwable) o).getMessage());
		} else {
			throw new RuntimeException(className + ":" + o.toString());
		}
	}

	public static long getTimeInMillis(Object o) {
		long timeInMillis = 0L;
		if (isEmpty(o)) {
			throwRuntimeException("object is null.");
		} else if (o instanceof java.sql.Date) {
			timeInMillis = ((java.sql.Date) o).getTime();
		} else if (o instanceof java.sql.Time) {
			timeInMillis = ((java.sql.Time) o).getTime();
		} else if (o instanceof java.sql.Timestamp) {
			timeInMillis = ((java.sql.Timestamp) o).getTime();
		} else if (o instanceof java.util.Date) {
			timeInMillis = ((java.util.Date) o).getTime();
		} else if (o instanceof java.util.GregorianCalendar) {
			timeInMillis = ((java.util.GregorianCalendar) o).getTimeInMillis();
		} else if (o instanceof java.util.Calendar) {
			timeInMillis = ((java.util.Calendar) o).getTimeInMillis();
		} else if (o instanceof java.lang.Number) {
			timeInMillis = ((java.lang.Number) o).longValue();
		} else {
			throwRuntimeException("not date/time/number type.");
		}
		return timeInMillis;
	}

	public static String formatDateToGMTString(Object o) {
		java.text.DateFormat dateFormat = java.text.DateFormat.getDateTimeInstance();
		dateFormat.setTimeZone(java.util.TimeZone.getTimeZone("GMT"));
		return dateFormat.format(new java.util.Date(getTimeInMillis(o)));
	}

	public static String formatDateToString(Object o) {
		return formatDateToString(o, null, null);
	}

	public static String formatDateToString(Object o, String formatString) {
		return formatDateToString(o, formatString, null);
	}

	public static String formatDateToString(Object o, String formatString, java.util.Locale locale) {
		String dateString = "";
		if (isEmpty(formatString)) {
			formatString = FORMATSTRING_DEFAULT;
		}
		if (isEmpty(locale)) {
			locale = LOCALE_DEFAULT;
		}
		try {
			long timeInMillis = getTimeInMillis(o);
			java.text.DateFormat dateFormat = new java.text.SimpleDateFormat(formatString, locale);
			dateString = dateFormat.format(new java.util.Date(timeInMillis));
		} catch (Exception e) {
			throwRuntimeException(e);
		}
		return dateString;
	}

	private static java.util.Date parseStringToUtilDateTry(String dateString, String formatString,
			java.util.Locale locale) {
		java.util.Date date = null;
		java.text.DateFormat dateFormat = null;
		try {
			dateFormat = new java.text.SimpleDateFormat(formatString, locale);
			date = dateFormat.parse(dateString);
		} catch (java.text.ParseException e1) {
			try {
				dateFormat = new java.text.SimpleDateFormat(FORMATSTRING_DEFAULT, locale);
				date = dateFormat.parse(dateString);
			} catch (java.text.ParseException e2) {
				try {
					dateFormat = new java.text.SimpleDateFormat(FORMATSTRING_DATE, locale);
					date = dateFormat.parse(dateString);
				} catch (java.text.ParseException e3) {
					try {
						dateFormat = new java.text.SimpleDateFormat(FORMATSTRING_DATE_TIME, locale);
						date = dateFormat.parse(dateString);
					} catch (java.text.ParseException e4) {
						try {
							dateFormat = new java.text.SimpleDateFormat(FORMATSTRING_TIME, locale);
							date = dateFormat.parse(dateString);
						} catch (java.text.ParseException e5) {
							try {
								dateFormat = new java.text.SimpleDateFormat(FORMATSTRING_TIME_LONG, locale);
								date = dateFormat.parse(dateString);
							} catch (java.text.ParseException e6) {
								try {
									dateFormat = new java.text.SimpleDateFormat(FORMATSTRING_LONG, locale);
									date = dateFormat.parse(dateString);
								} catch (java.text.ParseException e7) {
									try {
										dateFormat = new java.text.SimpleDateFormat(FORMATSTRING_STRING, locale);
										date = dateFormat.parse(dateString);
									} catch (java.text.ParseException e8) {
										try {
											dateFormat = new java.text.SimpleDateFormat(FORMATSTRING_STRING_Z, locale);
											date = dateFormat.parse(dateString);
										} catch (java.text.ParseException e9) {
											try {
												dateFormat = new java.text.SimpleDateFormat(FORMATSTRING_FULL, locale);
												date = dateFormat.parse(dateString);
											} catch (java.text.ParseException e10) {
												throwRuntimeException(e10);
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}
		return date;
	}

	public static java.util.Date parseStringToDate(String dateString) {
		return parseStringToDate(dateString, null, null);
	}

	public static java.util.Date parseStringToDate(String dateString, String formatString) {
		return parseStringToDate(dateString, formatString, null);
	}

	public static java.util.Date parseStringToDate(String dateString, String formatString, java.util.Locale locale) {
		if (isEmpty(dateString)) {
			throwRuntimeException("object is null.");
		}
		if (isEmpty(formatString)) {
			formatString = FORMATSTRING_DEFAULT;
		}
		if (isEmpty(locale)) {
			locale = LOCALE_DEFAULT;
		}
		return parseStringToUtilDateTry(dateString, formatString, locale);
	}

	public static java.util.Calendar convertToCalendar(Object o) {
		return (java.util.Calendar) convertToOtherClass(o, java.util.Calendar.class);
	}

	public static java.util.Date convertToUtilDate(Object o) {
		return (java.util.Date) convertToOtherClass(o, java.util.Date.class);
	}

	public static java.sql.Timestamp convertToSqlTimestamp(Object o) {
		return (java.sql.Timestamp) convertToOtherClass(o, java.sql.Timestamp.class);
	}

	@SuppressWarnings("rawtypes")
	public static Object convertToOtherClass(Object o, Class clazz) {
		Object target = null;
		long timeInMillis = getTimeInMillis(o);
		if (isEmpty(clazz)) {
			target = java.util.Calendar.getInstance();
			((java.util.Calendar) target).setTimeInMillis(timeInMillis);
		} else if (clazz.equals(java.sql.Date.class)) {
			target = new java.sql.Date(timeInMillis);
		} else if (clazz.equals(java.sql.Time.class)) {
			target = new java.sql.Time(timeInMillis);
		} else if (clazz.equals(java.sql.Timestamp.class)) {
			target = new java.sql.Timestamp(timeInMillis);
		} else if (clazz.equals(java.util.Date.class)) {
			target = new java.util.Date(timeInMillis);
		} else if (clazz.equals(java.util.GregorianCalendar.class)) {
			target = java.util.GregorianCalendar.getInstance();
			((java.util.GregorianCalendar) target).setTimeInMillis(timeInMillis);
			timeInMillis = ((java.util.GregorianCalendar) target).getTimeInMillis();
		} else if (clazz.equals(java.util.Calendar.class)) {
			target = java.util.Calendar.getInstance();
			((java.util.Calendar) target).setTimeInMillis(timeInMillis);
		} else {
			if (!clazz.getSuperclass().equals(java.lang.Object.class)) {
				target = convertToOtherClass(o, clazz.getSuperclass());
			} else {
				throwRuntimeException("not date / time type.");
			}
		}
		return target;
	}

	public static long getInterval(Object from, Object thru) {
		return getTimeInMillis(thru) - getTimeInMillis(from);
	}

	public static double getIntervalHours(Object from, Object thru) {
		return getInterval(from, thru) * 1.0 / MILLIS_IN_HOUR;
	}

	public static double getIntervalDays(Object from, Object thru) {
		return getInterval(from, thru) * 1.0 / MILLIS_IN_DAY;
	}

	@SuppressWarnings("rawtypes")
	public static Object getNow(Class clazz) {
		if (isEmpty(clazz)) {
			clazz = java.util.Calendar.class;
		}
		return convertToOtherClass(new java.util.Date(java.lang.System.currentTimeMillis()), clazz);
	}

	public static java.util.Date getNowUtilDate() {
		return (java.util.Date) getNow(java.util.Date.class);
	}

	public static java.sql.Date getNowSqlDate() {
		return (java.sql.Date) getNow(java.sql.Date.class);
	}

	public static java.sql.Time getNowSqlTime() {
		return (java.sql.Time) getNow(java.sql.Time.class);
	}

	public static java.sql.Timestamp getNowSqlTimestamp() {
		return (java.sql.Timestamp) getNow(java.sql.Timestamp.class);
	}

	public static java.util.Calendar getNowCalendar() {
		return (java.util.Calendar) getNow(java.util.Calendar.class);
	}

	public static String getNowString() {
		return getNowString(FORMATSTRING_STRING, null);
	}

	public static String getNowString(String formatString) {
		return getNowString(formatString, null);
	}

	public static String getNowString(String formatString, java.util.Locale locale) {
		return formatDateToString(getNow(java.util.Date.class), formatString, locale);
	}

	public static boolean checkLeapYear(int year) {
		java.util.GregorianCalendar calendar = new java.util.GregorianCalendar();
		return calendar.isLeapYear(year);
	}

	public static int getDaysInMonth(Object o) {
		java.util.Calendar calendar = java.util.Calendar.getInstance();
		calendar.setTimeInMillis(getTimeInMillis(o));
		return calendar.getActualMaximum(java.util.Calendar.DAY_OF_MONTH);
	}

	public static int getDaysInMonthByHand(Object o) {
		int days = 0;
		long timeInMillis = getTimeInMillis(o);
		java.util.Calendar calendar = java.util.Calendar.getInstance();
		calendar.setTimeInMillis(timeInMillis);
		int month = calendar.get(java.util.Calendar.MONTH);
		if (month == java.util.Calendar.JANUARY || month == java.util.Calendar.MARCH || month == java.util.Calendar.MAY
				|| month == java.util.Calendar.JULY || month == java.util.Calendar.AUGUST
				|| month == java.util.Calendar.OCTOBER || month == java.util.Calendar.DECEMBER) {
			days = 31;
		} else if (month == java.util.Calendar.APRIL || month == java.util.Calendar.JUNE
				|| month == java.util.Calendar.SEPTEMBER || month == java.util.Calendar.NOVEMBER) {
			days = 30;
		} else if (month == java.util.Calendar.FEBRUARY) {
			int year = calendar.get(java.util.Calendar.YEAR);
			if (checkLeapYear(year)) {
				days = 29;
			} else {
				days = 28;
			}
		}
		return days;
	}

	public static int getQuarterInYear(int month) {
		return month / 3 + 1;
	}

	public static int getQuarterInYear12(int month) {
		return getQuarterInYear(month - 1);
	}

	public static int getHalfInYear(int month) {
		return month / 6 + 1;
	}

	public static int getHalfInYear12(int month) {
		return getQuarterInYear(month - 1);
	}

	public static Object addHoursToTarget(Object target, int hours) {
		return addTimeToTarget(target, java.util.Calendar.HOUR_OF_DAY, hours);
	}

	public static Object addDaysToTarget(Object target, int days) {
		return addTimeToTarget(target, java.util.Calendar.DAY_OF_MONTH, days);
	}

	public static Object addTimeToTarget(Object target, int field, int amount) {
		java.util.Calendar targetCalendar = convertToCalendar(target);
		targetCalendar.add(field, amount);
		return convertToOtherClass(targetCalendar, target.getClass());
	}

	private static java.util.Calendar getAppointTimeTry(Object target, String dateString, String formatString,
			String highTimeField) {
		if (isEmpty(dateString) || isEmpty(formatString)) {
			return convertToCalendar(target);
		}
		java.util.Calendar targetCalendar = java.util.Calendar.getInstance();
		targetCalendar.setTimeInMillis(getTimeInMillis(target));
		java.util.Calendar appointCalendar = java.util.Calendar.getInstance();
		appointCalendar.setTimeInMillis(parseStringToDate(dateString, formatString).getTime());

		if (TIME_UNIT[8].equalsIgnoreCase(highTimeField)) {
			targetCalendar.set(java.util.Calendar.YEAR, appointCalendar.get(java.util.Calendar.YEAR));
			highTimeField = TIME_UNIT[6];
		}
		if (TIME_UNIT[6].equalsIgnoreCase(highTimeField)) {
			targetCalendar.set(java.util.Calendar.MONTH, appointCalendar.get(java.util.Calendar.MONTH));
			highTimeField = TIME_UNIT[4];
		}
		if (TIME_UNIT[4].equalsIgnoreCase(highTimeField)) {
			targetCalendar.set(java.util.Calendar.DAY_OF_MONTH, appointCalendar.get(java.util.Calendar.DAY_OF_MONTH));
			highTimeField = TIME_UNIT[3];
		}
		if (TIME_UNIT[3].equalsIgnoreCase(highTimeField)) {
			targetCalendar.set(java.util.Calendar.HOUR_OF_DAY, appointCalendar.get(java.util.Calendar.HOUR_OF_DAY));
			highTimeField = TIME_UNIT[2];
		}
		if (TIME_UNIT[2].equalsIgnoreCase(highTimeField)) {
			targetCalendar.set(java.util.Calendar.MINUTE, appointCalendar.get(java.util.Calendar.MINUTE));
			highTimeField = TIME_UNIT[1];
		}
		if (TIME_UNIT[1].equalsIgnoreCase(highTimeField)) {
			targetCalendar.set(java.util.Calendar.SECOND, appointCalendar.get(java.util.Calendar.SECOND));
			highTimeField = TIME_UNIT[0];
		}
		if (TIME_UNIT[0].equalsIgnoreCase(highTimeField)) {
			targetCalendar.set(java.util.Calendar.MILLISECOND, appointCalendar.get(java.util.Calendar.MILLISECOND));
		}
		return targetCalendar;
	}

	public static Object getAppointTime(Object target, String dateString, String formatString, String highTimeField) {
		return convertToOtherClass(getAppointTimeTry(target, dateString, formatString, highTimeField),
				target.getClass());
	}

	public static Object getStartHour(Object target) {
		return getStartTime(target, TIME_UNIT[2]);
	}

	public static Object getStartDay(Object target) {
		return getStartTime(target, TIME_UNIT[3]);
	}

	public static Object getStartWeek(Object target) {
		return getStartTime(target, TIME_UNIT[5]);
	}

	public static Object getStartMonth(Object target) {
		return getStartTime(target, TIME_UNIT[4]);
	}

	public static Object getStartQuarter(Object target) {
		return getStartTime(target, TIME_UNIT[7]);
	}

	public static Object getStartHalf(Object target) {
		java.util.Calendar targetCalendar = java.util.Calendar.getInstance();
		targetCalendar.setTimeInMillis(getTimeInMillis(target));
		int month = getHalfInYear(targetCalendar.get(java.util.Calendar.MONTH)) * 6 - 5;
		String formatString = "MM-dd HH:mm:ss:SSS";
		String highTimeField = TIME_UNIT[6];
		String dateString = month + "-01 00:00:00:000";
		return convertToOtherClass(getAppointTimeTry(targetCalendar, dateString, formatString, highTimeField),
				target.getClass());
	}

	public static Object getStartYear(Object target) {
		return getStartTime(target, TIME_UNIT[6]);
	}

	public static Object getEndHour(Object target) {
		return getEndTime(target, TIME_UNIT[2]);
	}

	public static Object getEndDay(Object target) {
		return getEndTime(target, TIME_UNIT[3]);
	}

	public static Object getEndWeek(Object target) {
		return getEndTime(target, TIME_UNIT[5]);
	}

	public static Object getEndMonth(Object target) {
		return getEndTime(target, TIME_UNIT[4]);
	}

	public static Object getEndQuarter(Object target) {
		return getEndTime(target, TIME_UNIT[7]);
	}

	public static Object getEndHalf(Object target) {
		java.util.Calendar targetCalendar = java.util.Calendar.getInstance();
		targetCalendar.setTimeInMillis(getTimeInMillis(target));
		int month = getHalfInYear(targetCalendar.get(java.util.Calendar.MONTH)) * 6;
		targetCalendar.set(java.util.Calendar.MONTH, month - 1);
		String formatString = "MM-dd HH:mm:ss:SSS";
		String highTimeField = TIME_UNIT[6];
		String dateString = month + "-" + getDaysInMonth(targetCalendar) + " 23:59:59:999";
		return convertToOtherClass(getAppointTimeTry(targetCalendar, dateString, formatString, highTimeField),
				target.getClass());
	}

	public static Object getEndYear(Object target) {
		return getEndTime(target, TIME_UNIT[6]);
	}

	public static Object getStartTime(Object target, String subTimeField) {
		String dateString = "";
		String formatString = "";
		String highTimeField = "";
		java.util.Calendar targetCalendar = java.util.Calendar.getInstance();
		targetCalendar.setTimeInMillis(getTimeInMillis(target));
		if (TIME_UNIT[0].equalsIgnoreCase(subTimeField)) {
			highTimeField = TIME_UNIT[0];
			formatString = "SSS";
			dateString = "000";
		} else if (TIME_UNIT[1].equalsIgnoreCase(subTimeField)) {
			highTimeField = TIME_UNIT[1];
			formatString = "ss:SSS";
			dateString = "00:000";
		} else if (TIME_UNIT[2].equalsIgnoreCase(subTimeField)) {
			highTimeField = TIME_UNIT[2];
			formatString = "mm:ss:SSS";
			dateString = "00:00:000";
		} else if (TIME_UNIT[3].equalsIgnoreCase(subTimeField)) {
			highTimeField = TIME_UNIT[3];
			formatString = "HH:mm:ss:SSS";
			dateString = "00:00:00:000";
		} else if (TIME_UNIT[4].equalsIgnoreCase(subTimeField)) {
			highTimeField = TIME_UNIT[4];
			formatString = "dd HH:mm:ss:SSS";
			dateString = "01 00:00:00:000";
		} else if (TIME_UNIT[5].equalsIgnoreCase(subTimeField)) {
			highTimeField = TIME_UNIT[4];
			formatString = "dd HH:mm:ss:SSS";
			targetCalendar.set(java.util.Calendar.DAY_OF_WEEK, targetCalendar.getFirstDayOfWeek());
			int day = targetCalendar.get(java.util.Calendar.DAY_OF_MONTH);
			dateString = day + " 00:00:00:000";
		} else if (TIME_UNIT[6].equalsIgnoreCase(subTimeField)) {
			highTimeField = TIME_UNIT[6];
			formatString = "MM-dd HH:mm:ss:SSS";
			dateString = "01-01 00:00:00:000";
		} else if (TIME_UNIT[7].equalsIgnoreCase(subTimeField)) {
			highTimeField = TIME_UNIT[6];
			formatString = "MM-dd HH:mm:ss:SSS";
			int month = getQuarterInYear(targetCalendar.get(java.util.Calendar.MONTH)) * 3 - 2;
			dateString = month + "-01 00:00:00:000";
		} else if (TIME_UNIT[8].equalsIgnoreCase(subTimeField)) {
			highTimeField = TIME_UNIT[8];
			formatString = "yyyy-MM-dd HH:mm:ss:SSS";
			int year = targetCalendar.get(java.util.Calendar.YEAR) - 1;
			dateString = year + "-01-01 00:00:00:000";
		} else if (TIME_UNIT[9].equalsIgnoreCase(subTimeField)) {
			highTimeField = TIME_UNIT[8];
			formatString = "yyyy-MM-dd HH:mm:ss:SSS";
			int year = targetCalendar.get(java.util.Calendar.YEAR) - 10;
			dateString = year + "-01-01 00:00:00:000";
		} else if (TIME_UNIT[10].equalsIgnoreCase(subTimeField)) {
			highTimeField = TIME_UNIT[8];
			formatString = "yyyy-MM-dd HH:mm:ss:SSS";
			int year = targetCalendar.get(java.util.Calendar.YEAR) - 100;
			dateString = year + "-01-01 00:00:00:000";
		} else if (TIME_UNIT[11].equalsIgnoreCase(subTimeField)) {
			highTimeField = TIME_UNIT[8];
			formatString = "yyyy-MM-dd HH:mm:ss:SSS";
			int year = targetCalendar.get(java.util.Calendar.YEAR) - 1000;
			dateString = year + "-01-01 00:00:00:000";
		} else if (TIME_UNIT[12].equalsIgnoreCase(subTimeField)) {
			highTimeField = TIME_UNIT[8];
			formatString = "yyyy-MM-dd HH:mm:ss:SSS";
			targetCalendar.setTimeInMillis(0L);
			int year = targetCalendar.get(java.util.Calendar.YEAR);
			dateString = year + "-01-01 00:00:00:000";
		} else {
			throwRuntimeException(
					"add time field is not match,allows type(millis,second,minute,hour,day,week,month,quarter,year,decade,century,millennium).");
		}
		return convertToOtherClass(getAppointTimeTry(targetCalendar, dateString, formatString, highTimeField),
				target.getClass());
	}

	public static Object getEndTime(Object target, String subTimeField) {
		String dateString = "";
		String formatString = "";
		String highTimeField = "";
		java.util.Calendar targetCalendar = java.util.Calendar.getInstance();
		targetCalendar.setTimeInMillis(getTimeInMillis(target));
		if (TIME_UNIT[0].equalsIgnoreCase(subTimeField)) {
			highTimeField = TIME_UNIT[0];
			formatString = "SSS";
			dateString = "999";
		} else if (TIME_UNIT[1].equalsIgnoreCase(subTimeField)) {
			highTimeField = TIME_UNIT[1];
			formatString = "ss:SSS";
			dateString = "59:999";
		} else if (TIME_UNIT[2].equalsIgnoreCase(subTimeField)) {
			highTimeField = TIME_UNIT[2];
			formatString = "mm:ss:SSS";
			dateString = "59:59:999";
		} else if (TIME_UNIT[3].equalsIgnoreCase(subTimeField)) {
			highTimeField = TIME_UNIT[3];
			formatString = "HH:mm:ss:SSS";
			dateString = "23:59:59:999";
		} else if (TIME_UNIT[4].equalsIgnoreCase(subTimeField)) {
			highTimeField = TIME_UNIT[4];
			formatString = "dd HH:mm:ss:SSS";
			dateString = getDaysInMonth(targetCalendar) + " 23:59:59:999";
		} else if (TIME_UNIT[5].equalsIgnoreCase(subTimeField)) {
			highTimeField = TIME_UNIT[4];
			formatString = "dd HH:mm:ss:SSS";
			targetCalendar.set(java.util.Calendar.DAY_OF_WEEK, targetCalendar.getFirstDayOfWeek() + 6);
			int day = targetCalendar.get(java.util.Calendar.DAY_OF_MONTH);
			dateString = day + " 23:59:59:999";
		} else if (TIME_UNIT[6].equalsIgnoreCase(subTimeField)) {
			highTimeField = TIME_UNIT[6];
			formatString = "MM-dd HH:mm:ss:SSS";
			targetCalendar.set(java.util.Calendar.MONTH, 11);
			dateString = "12-" + getDaysInMonth(targetCalendar) + " 23:59:59:999";
		} else if (TIME_UNIT[7].equalsIgnoreCase(subTimeField)) {
			highTimeField = TIME_UNIT[6];
			formatString = "MM-dd HH:mm:ss:SSS";
			int month = getQuarterInYear(targetCalendar.get(java.util.Calendar.MONTH)) * 3;
			dateString = month + "-" + getDaysInMonth(target) + " 23:59:59:999";
		} else if (TIME_UNIT[8].equalsIgnoreCase(subTimeField)) {
			highTimeField = TIME_UNIT[8];
			formatString = "yyyy-MM-dd HH:mm:ss:SSS";
			int year = targetCalendar.get(java.util.Calendar.YEAR) - 1;
			dateString = year + "-12-31 23:59:59:999";
		} else if (TIME_UNIT[9].equalsIgnoreCase(subTimeField)) {
			highTimeField = TIME_UNIT[8];
			formatString = "yyyy-MM-dd HH:mm:ss:SSS";
			int year = targetCalendar.get(java.util.Calendar.YEAR) - 10;
			dateString = year + "-12-31 23:59:59:999";
		} else if (TIME_UNIT[10].equalsIgnoreCase(subTimeField)) {
			highTimeField = TIME_UNIT[8];
			formatString = "yyyy-MM-dd HH:mm:ss:SSS";
			int year = targetCalendar.get(java.util.Calendar.YEAR) - 100;
			dateString = year + "-12-31 23:59:59:999";
		} else if (TIME_UNIT[11].equalsIgnoreCase(subTimeField)) {
			highTimeField = TIME_UNIT[8];
			formatString = "yyyy-MM-dd HH:mm:ss:SSS";
			int year = targetCalendar.get(java.util.Calendar.YEAR) - 1000;
			dateString = year + "-12-31 23:59:59:999";
		} else if (TIME_UNIT[12].equalsIgnoreCase(subTimeField)) {
			highTimeField = TIME_UNIT[8];
			formatString = "yyyy-MM-dd HH:mm:ss:SSS";
			targetCalendar.setTimeInMillis(0L);
			int year = targetCalendar.get(java.util.Calendar.YEAR);
			dateString = year + "-12-31 23:59:59:999";
		} else {
			throwRuntimeException(
					"add time field is not match,allows type(millis,second,minute,hour,day,week,month,quarter,year,decade,century,millennium).");
		}
		return convertToOtherClass(getAppointTimeTry(targetCalendar, dateString, formatString, highTimeField),
				target.getClass());
	}

	public static java.util.Calendar getCalendarBySeparate(Integer yearFull, Integer month, Integer day, Integer hour,
			Integer minute, Integer second, Integer millis) {
		return (java.util.Calendar) getTimeBySeparate(java.util.Calendar.class, yearFull, month, day, hour, minute,
				second, millis);
	}

	public static java.util.Date getUtilDateBySeparate(Integer yearFull, Integer month, Integer day, Integer hour,
			Integer minute, Integer second, Integer millis) {
		return (java.util.Date) getTimeBySeparate(java.util.Date.class, yearFull, month, day, hour, minute, second,
				millis);
	}

	public static java.sql.Date getSqlDateBySeparate(Integer yearFull, Integer month, Integer day, Integer hour,
			Integer minute, Integer second, Integer millis) {
		return (java.sql.Date) getTimeBySeparate(java.sql.Date.class, yearFull, month, day, hour, minute, second,
				millis);
	}

	public static java.sql.Time getSqlTimeBySeparate(Integer yearFull, Integer month, Integer day, Integer hour,
			Integer minute, Integer second, Integer millis) {
		return (java.sql.Time) getTimeBySeparate(java.sql.Time.class, yearFull, month, day, hour, minute, second,
				millis);
	}

	public static java.sql.Timestamp getSqlTimestampBySeparate(Integer yearFull, Integer month, Integer day,
			Integer hour, Integer minute, Integer second, Integer millis) {
		return (java.sql.Timestamp) getTimeBySeparate(java.sql.Timestamp.class, yearFull, month, day, hour, minute,
				second, millis);
	}

	@SuppressWarnings("rawtypes")
	private static Object getTimeBySeparate(Class clazz, Integer yearFull, Integer month, Integer day, Integer hour,
			Integer minute, Integer second, Integer millis) {
		if (isEmpty(clazz)) {
			clazz = java.util.Calendar.class;
		}
		if (isEmpty(yearFull)) {
			yearFull = 1970;
		}
		if (isEmpty(month)) {
			month = 0;
		}
		if (isEmpty(day)) {
			day = 1;
		}
		if (isEmpty(hour)) {
			hour = 0;
		}
		if (isEmpty(minute)) {
			minute = 0;
		}
		if (isEmpty(second)) {
			second = 0;
		}
		if (isEmpty(millis)) {
			millis = 0;
		}
		java.util.Calendar calendar = java.util.Calendar.getInstance();
		calendar.set(yearFull, month, day, hour, minute, second);
		calendar.set(java.util.Calendar.MILLISECOND, millis);
		return convertToOtherClass(calendar, clazz);
	}

	public static java.util.List<String> getWeekNames(java.util.Locale locale) {
		if (isEmpty(locale)) {
			locale = LOCALE_DEFAULT;
		}
		java.util.Calendar calendar = java.util.Calendar.getInstance(locale);
		calendar.set(java.util.Calendar.DAY_OF_WEEK, calendar.getFirstDayOfWeek());
		java.text.SimpleDateFormat dateFormat = new java.text.SimpleDateFormat("EEEE", locale);
		java.util.List<String> resultList = new java.util.ArrayList<String>();
		for (int i = 0; i < 7; i++) {
			resultList.add(dateFormat.format(calendar.getTime()));
			calendar.roll(java.util.Calendar.DAY_OF_WEEK, 1);
		}
		return resultList;
	}

	public static java.util.List<String> getMonthNames(java.util.Locale locale) {
		if (isEmpty(locale)) {
			locale = LOCALE_DEFAULT;
		}
		java.util.Calendar calendar = java.util.Calendar.getInstance(locale);
		calendar.set(java.util.Calendar.MONTH, java.util.Calendar.JANUARY);
		java.text.SimpleDateFormat dateFormat = new java.text.SimpleDateFormat("MMMM", locale);
		java.util.List<String> resultList = new java.util.ArrayList<String>();
		for (int i = java.util.Calendar.JANUARY; i <= calendar.getActualMaximum(java.util.Calendar.MONTH); i++) {
			resultList.add(dateFormat.format(calendar.getTime()));
			calendar.roll(java.util.Calendar.MONTH, 1);
		}
		return resultList;
	}

	public static java.util.TimeZone getTimeZone(String tzId) {
		java.util.TimeZone timeZone = null;
		if (isEmpty(tzId)) {
			timeZone = java.util.TimeZone.getDefault();
		} else {
			timeZone = java.util.TimeZone.getTimeZone(tzId);
		}
		return timeZone;
	}

	private static int compareTo(Object object1, Object object2) {
		int result = 0;
		long intervalInMillis = getInterval(object2, object1);
		if (intervalInMillis > 0) {
			result = 1;
		} else if (intervalInMillis < 0) {
			result = -1;
		}
		return result;
	}

	public static int before(Object object1, Object object2) {
		return compareTo(object2, object1);
	}

	public static int after(Object object1, Object object2) {
		return compareTo(object1, object2);
	}

	public static boolean equalTime(Object object1, Object object2) {
		boolean result = false;
		if (compareTo(object1, object2) == 0) {
			result = true;
		}
		return result;
	}

	public static boolean equalStrict(Object object1, Object object2) {
		boolean result = false;
		if (object1.getClass() == object2.getClass()) {
			result = equalTime(object1, object2);
		}
		return result;
	}

	public static java.util.Calendar changeLenient(java.util.Calendar calendar, boolean lenient) {
		if (calendar.isLenient() == lenient) {
			return calendar;
		} else {
			calendar.setLenient(lenient);
			return calendar;
		}
	}

	public static final java.util.Map<String, Integer> convertLunarToSolar(int year, int month, int day,
			boolean isLeap) {
		return LunarCalendar.convertLunarToSolar(year, month, day, isLeap);
	}

	public static java.util.Map<String, Integer> convertSolarToLunar(int year, int month, int day) {
		return LunarCalendar.convertSolarToLunar(year, month, day);
	}

	public static String getLunarStringBySolar(int year, int month, int day) {
		return LunarCalendar.getLunarStringBySolar(year, month, day);
	}

	public static final String getZodiacByYear(int year, int month, int day) {
		java.util.Map<String, Integer> lunarDate = convertSolarToLunar(year, month, day);
		return LunarCalendar.getZodiacByYear(lunarDate.get(TIME_UNIT[8]));
	}

	public static final String getGossipByuYear(int year, int month, int day) {
		java.util.Map<String, Integer> lunarDate = convertSolarToLunar(year, month, day);
		return LunarCalendar.getGossipByuYear(lunarDate.get(TIME_UNIT[8]));
	}

	public static String toString(Object o, String formatString) {
		if (isEmpty(formatString)) {
			formatString = FORMATSTRING_LONG;
		}
		java.util.Calendar calendar = convertToCalendar(o);
		String result = "阳历时间： " + formatDateToString(calendar, formatString);
		result += "\n阴历时间： " + getLunarStringBySolar(calendar.get(java.util.Calendar.YEAR),
				calendar.get(java.util.Calendar.MONTH), calendar.get(java.util.Calendar.DAY_OF_MONTH));
		return result;
	}

	public static String toString(Object o) {
		return toString(o, null);
	}

	private static class LunarCalendar {

		private static final long serialVersionUID = -945939951837309867L;

		/**
		 * 支持转换的最小农历年份
		 */
		public static final int YEAR_MIN = 1900;

		/**
		 * 支持转换的最大农历年份
		 */
		public static final int YEAR_MAX = 2099;

		/**
		 * 公历每月前的天数
		 */
		private static final int DAYS_BEFORE_MONTH[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };

		/**
		 * 用来表示1900年到2099年间农历年份的相关信息，共24位bit的16进制表示， 其中： 1. 前4位表示该年闰哪个月；
		 * 2.5-17位表示农历年份13个月的大小月分布，0表示小，1表示大； 3. 最后7位表示农历年首（正月初一）对应的公历日期。
		 * 以2014年的数据0x955ABF为例说明： 1001 0101 0101 1010 1011 1111 闰九月
		 * 农历正月初一对应公历1月31号
		 */
		private static final int LUNAR_INFO[] = { 0x84B6BF, /* 1900 */
				0x04AE53, 0x0A5748, 0x5526BD, 0x0D2650, 0x0D9544, 0x46AAB9, 0x056A4D, 0x09AD42, 0x24AEB6,
				0x04AE4A, /*
							 * 1901 - 1910
							 */
				0x6A4DBE, 0x0A4D52, 0x0D2546, 0x5D52BA, 0x0B544E, 0x0D6A43, 0x296D37, 0x095B4B, 0x749BC1,
				0x049754, /*
							 * 1911 - 1920
							 */
				0x0A4B48, 0x5B25BC, 0x06A550, 0x06D445, 0x4ADAB8, 0x02B64D, 0x095742, 0x2497B7, 0x04974A,
				0x664B3E, /*
							 * 1921 - 1930
							 */
				0x0D4A51, 0x0EA546, 0x56D4BA, 0x05AD4E, 0x02B644, 0x393738, 0x092E4B, 0x7C96BF, 0x0C9553,
				0x0D4A48, /*
							 * 1931 - 1940
							 */
				0x6DA53B, 0x0B554F, 0x056A45, 0x4AADB9, 0x025D4D, 0x092D42, 0x2C95B6, 0x0A954A, 0x7B4ABD,
				0x06CA51, /*
							 * 1941 - 1950
							 */
				0x0B5546, 0x555ABB, 0x04DA4E, 0x0A5B43, 0x352BB8, 0x052B4C, 0x8A953F, 0x0E9552, 0x06AA48,
				0x6AD53C, /*
							 * 1951 - 1960
							 */
				0x0AB54F, 0x04B645, 0x4A5739, 0x0A574D, 0x052642, 0x3E9335, 0x0D9549, 0x75AABE, 0x056A51,
				0x096D46, /*
							 * 1961 - 1970
							 */
				0x54AEBB, 0x04AD4F, 0x0A4D43, 0x4D26B7, 0x0D254B, 0x8D52BF, 0x0B5452, 0x0B6A47, 0x696D3C,
				0x095B50, /*
							 * 1971 - 1980
							 */
				0x049B45, 0x4A4BB9, 0x0A4B4D, 0xAB25C2, 0x06A554, 0x06D449, 0x6ADA3D, 0x0AB651, 0x095746,
				0x5497BB, /*
							 * 1981 - 1990
							 */
				0x04974F, 0x064B44, 0x36A537, 0x0EA54A, 0x86B2BF, 0x05AC53, 0x0AB647, 0x5936BC, 0x092E50,
				0x0C9645, /*
							 * 1991 - 2000
							 */
				0x4D4AB8, 0x0D4A4C, 0x0DA541, 0x25AAB6, 0x056A49, 0x7AADBD, 0x025D52, 0x092D47, 0x5C95BA,
				0x0A954E, /*
							 * 2001 - 2010
							 */
				0x0B4A43, 0x4B5537, 0x0AD54A, 0x955ABF, 0x04BA53, 0x0A5B48, 0x652BBC, 0x052B50, 0x0A9345,
				0x474AB9, /*
							 * 2011 - 2020
							 */
				0x06AA4C, 0x0AD541, 0x24DAB6, 0x04B64A, 0x6a573D, 0x0A4E51, 0x0D2646, 0x5E933A, 0x0D534D,
				0x05AA43, /*
							 * 2021 - 2030
							 */
				0x36B537, 0x096D4B, 0xB4AEBF, 0x04AD53, 0x0A4D48, 0x6D25BC, 0x0D254F, 0x0D5244, 0x5DAA38,
				0x0B5A4C, /*
							 * 2031 - 2040
							 */
				0x056D41, 0x24ADB6, 0x049B4A, 0x7A4BBE, 0x0A4B51, 0x0AA546, 0x5B52BA, 0x06D24E, 0x0ADA42,
				0x355B37, /*
							 * 2041 - 2050
							 */
				0x09374B, 0x8497C1, 0x049753, 0x064B48, 0x66A53C, 0x0EA54F, 0x06AA44, 0x4AB638, 0x0AAE4C,
				0x092E42, /*
							 * 2051 - 2060
							 */
				0x3C9735, 0x0C9649, 0x7D4ABD, 0x0D4A51, 0x0DA545, 0x55AABA, 0x056A4E, 0x0A6D43, 0x452EB7,
				0x052D4B, /*
							 * 2061 - 2070
							 */
				0x8A95BF, 0x0A9553, 0x0B4A47, 0x6B553B, 0x0AD54F, 0x055A45, 0x4A5D38, 0x0A5B4C, 0x052B42,
				0x3A93B6, /*
							 * 2071 - 2080
							 */
				0x069349, 0x7729BD, 0x06AA51, 0x0AD546, 0x54DABA, 0x04B64E, 0x0A5743, 0x452738, 0x0D264A,
				0x8E933E, /*
							 * 2081 - 2090
							 */
				0x0D5252, 0x0DAA47, 0x66B53B, 0x056D4F, 0x04AE45, 0x4A4EB9, 0x0A4D4C, 0x0D1541,
				0x2D92B5 /*
							 * 2091 - 2099
							 */
		};

		private static final String[] ZODIACS = new String[] { "鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊", "猴", "鸡", "狗",
				"猪" };

		private static final String[] GOSSIP_GAN = new String[] { "甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸" };

		private static final String[] GOSSIP_ZHI = new String[] { "子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌",
				"亥" };

		private static final String[] MONTH_LUNAR = { "正月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "冬月",
				"腊月" };

		private static final String[] DAY_LUNAR_PRE = { "初", "十", "廿", "卅" };

		private static final String[] DAY_LUNAR_SUF = { " ", "一", "二", "三", "四", "五", "六", "七", "八", "九" };

		/**
		 * 将农历日期转换为公历日期
		 * 
		 * @param year农历年份
		 * @param month农历月
		 * @param monthDay农历日
		 * @param isLeap该月是否是闰月
		 * @return 返回农历日期对应的公历日期Map
		 */
		public static java.util.Map<String, Integer> convertLunarToSolar(int year, int month, int day, boolean isLeap) {
			checkValueRange(year, YEAR_MIN, YEAR_MAX);
			checkValueRange(month, 1, 12);
			checkValueRange(day, 1, getDaysInLunarMonth(year, month, isLeap));
			java.util.Map<String, Integer> solarDate = new java.util.HashMap<String, Integer>();
			int iYear = year;
			int iMonth = 0;
			int iDay = 0;

			int leapMonth = 0;
			int dayOffset = (LUNAR_INFO[iYear - YEAR_MIN] & 0x001F) - 1;
			if (((LUNAR_INFO[iYear - YEAR_MIN] & 0x0060) >> 5) == 2) {
				dayOffset += 31;
			}
			for (int i = 1; i < month; i++) {
				if ((LUNAR_INFO[iYear - YEAR_MIN] & (0x80000 >> (i - 1))) == 0)
					dayOffset += 29;
				else
					dayOffset += 30;
			}
			dayOffset += day;
			leapMonth = (LUNAR_INFO[iYear - YEAR_MIN] & 0xf00000) >> 20;

			// 有闰月
			if (leapMonth != 0) {
				if (month > leapMonth || (month == leapMonth && isLeap)) {
					if ((LUNAR_INFO[iYear - YEAR_MIN] & (0x80000 >> (month - 1))) == 0)
						dayOffset += 29;
					else
						dayOffset += 30;
				}
			}

			if (dayOffset > 366 || (iYear % 4 != 0 && dayOffset > 365)) {
				iYear += 1;
				if (iYear % 4 == 1)
					dayOffset -= 366;
				else
					dayOffset -= 365;
			}

			for (int i = 1; i < 13; i++) {
				int iPos = DAYS_BEFORE_MONTH[i];
				if (iYear % 4 == 0 && i > 2) {
					iPos += 1;
				}

				if (iYear % 4 == 0 && i == 2 && iPos + 1 == dayOffset) {
					iMonth = i;
					iDay = dayOffset - 31;
					break;
				}

				if (iPos >= dayOffset) {
					iMonth = i;
					iPos = DAYS_BEFORE_MONTH[i - 1];
					if (iYear % 4 == 0 && i > 2) {
						iPos += 1;
					}
					if (dayOffset > iPos)
						iDay = dayOffset - iPos;
					else if (dayOffset == iPos) {
						if (iYear % 4 == 0 && i == 2)
							iDay = DAYS_BEFORE_MONTH[i] - DAYS_BEFORE_MONTH[i - 1] + 1;
						else
							iDay = DAYS_BEFORE_MONTH[i] - DAYS_BEFORE_MONTH[i - 1];

					} else
						iDay = dayOffset;
					break;
				}
			}
			solarDate.put(TIME_UNIT[8], iYear);
			solarDate.put(TIME_UNIT[6], iMonth);
			solarDate.put(TIME_UNIT[4], iDay);
			return solarDate;
		}

		/**
		 * 将公历日期转换为农历日期，且标识是否是闰月
		 * 
		 * @param year
		 * @param month
		 * @param day
		 * @return 返回公历日期对应的农历日期Map
		 */
		public static java.util.Map<String, Integer> convertSolarToLunar(int year, int month, int day) {
			java.util.Map<String, Integer> lunarDate = new java.util.HashMap<String, Integer>();
			java.util.Calendar baseCalendar = java.util.Calendar.getInstance();
			baseCalendar.set(1900, 0, 31);
			java.util.Calendar targetCalendar = java.util.Calendar.getInstance();
			targetCalendar.set(year, month - 1, day);
			checkValueRange(targetCalendar.get(java.util.Calendar.YEAR), YEAR_MIN, YEAR_MAX);

			int offset = (int) ((targetCalendar.getTimeInMillis() - baseCalendar.getTimeInMillis()) / MILLIS_IN_DAY);
			// 用offset减去每农历年的天数计算年
			int iYear = 0;
			int iMonth = 0;
			int iDay = 0;
			boolean isLeap = false;
			for (iYear = YEAR_MIN; iYear <= YEAR_MAX; iYear++) {
				int daysInYear = getDaysInLunarYear(iYear);
				offset -= daysInYear;
				if (offset < 0) {
					// 保留当年的天数
					offset += daysInYear;
					break;
				}
			}
			int leapMonth = getLeapMonth(iYear);
			// 用offset减去每农历月的天数计算月(13个月)
			for (iMonth = 1; iMonth <= 13; iMonth++) {
				int daysInMonth = getDaysInLunarMonth13(iYear, iMonth);
				offset -= daysInMonth;
				if (offset < 0) {
					// 保留当月的天数
					offset += daysInMonth;
					break;
				}
			}
			// 当前月超过闰月
			if (leapMonth != 0 && iMonth > leapMonth) {
				iMonth--;
				if (iMonth == leapMonth) {
					isLeap = true;
				}
			}
			iDay = offset + 1;

			lunarDate.put(TIME_UNIT[8], iYear);
			lunarDate.put(TIME_UNIT[6], iMonth);
			lunarDate.put(TIME_UNIT[4], iDay);
			lunarDate.put("ISLEAP", isLeap ? 1 : 0);
			return lunarDate;
		}

		/**
		 * 传回农历 year年的总天数
		 * 
		 * @param year将要计算的年份
		 * @return 返回传入年份的总天数
		 */
		public static int getDaysInLunarYear(int year) {
			int sum = 348;
			if (getLeapMonth(year) != 0) {
				sum = 377;
			}
			int monthInfo = LUNAR_INFO[year - YEAR_MIN] & 0x0FFF80;
			for (int i = 0x80000; i > 0x7; i >>= 1) {
				if ((monthInfo & i) != 0)
					sum += 1;
			}
			return sum;
		}

		/**
		 * 传回农历year年month月的总天数
		 * 
		 * @param year要计算的年份
		 * @param month要计算的月
		 * @param leap当月是否是闰月
		 * @return 传回天数.
		 */
		public static int getDaysInLunarMonth(int year, int month, boolean isLeap) {
			int days = 0;
			checkValueRange(month, 1, 12);
			int leapMonth = getLeapMonth(year);
			int offset = 0;
			if (leapMonth == 0) {
				offset = 0;
			} else if (isLeap && leapMonth == month) {
				offset = 1;
			} else if (month > leapMonth) {
				offset = 1;
			} else {
				offset = 0;
			}
			days = getDaysInLunarMonth13(year, month + offset);
			return days;
		}

		/**
		 * 传回农历 year年month月的总天数，总共有13个月包括闰月
		 * 
		 * @param year将要计算的年份
		 * @param month将要计算的月份
		 * @return 传回农历 year年month月的总天数
		 */
		private static int getDaysInLunarMonth13(int year, int month) {
			checkValueRange(year, YEAR_MIN, YEAR_MAX);
			checkValueRange(month, 1, 13);
			if ((LUNAR_INFO[year - YEAR_MIN] & (0x100000 >> month)) == 0)
				return 29;
			else
				return 30;
		}

		/**
		 * 传回农历 year年闰哪个月 1-12 , 没闰传回 0
		 * 
		 * @param year将要计算的年份
		 * @return 传回农历 year年闰哪个月1-12, 没闰传回 0
		 */
		public static int getLeapMonth(int year) {
			checkValueRange(year, YEAR_MIN, YEAR_MAX);
			return (int) (LUNAR_INFO[year - YEAR_MIN] & 0xF00000) >> 20;
		}

		private static void checkValueRange(int target, int min, int max) {
			if (target > max || target < min) {
				throwRuntimeException("Can calculate the range[" + min + "," + max + "]");
			}
		}

		/*
		 * 传入年 传回生肖
		 * 
		 * @param 阴历year
		 * 
		 * @return 生肖zodiac
		 */
		public static final String getZodiacByYear(int year) {
			return ZODIACS[(year - 4) % 12];
		}

		/*
		 * 传入年 传回干支
		 * 
		 * @param 阴历year
		 * 
		 * @return 干支Gossip_Gan+ Gossip_Zhi
		 */
		public static final String getGossipByuYear(int year) {
			int num = year - 1900 + 36;
			return (GOSSIP_GAN[num % 10] + GOSSIP_ZHI[num % 12]);
		}

		public static final String toString(int year, int month, int day, boolean isLeap) {
			int leapMonth = getLeapMonth(year);
			String result = year + "年" + (leapMonth == month && isLeap ? "闰" : "") + month + "月" + day + "号 ";
			result += "(";
			result += getGossipByuYear(year) + " " + getZodiacByYear(year) + "年 ";
			result += (leapMonth == month && isLeap ? "闰" : "") + MONTH_LUNAR[month - 1] + " ";
			result += DAY_LUNAR_PRE[(day / 10)] + DAY_LUNAR_SUF[day % 10];
			result += ")";
			return result;
		}

		public static final String getLunarStringBySolar(int year, int month, int day) {
			java.util.Map<String, Integer> lunarDate = convertSolarToLunar(year, month, day);
			return toString(lunarDate.get(TIME_UNIT[8]), lunarDate.get(TIME_UNIT[6]), lunarDate.get(TIME_UNIT[4]),
					lunarDate.get("ISLEAP") == 1 ? true : false);
		}

		@Override
		public String toString() {
			// TODO Auto-generated method stub
			return super.toString() + "[serialVersionUID:" + serialVersionUID;
		}
	}
}
